- Published on
Developing a Python Library for Symbolic Computation and Pedagogy | Getting Started
- Authors
- Name
- RezSat
- @rezsat
Alright, let's get into some coding. If you missed the backstory, check out the previous post here: Developing a Python Library for Symbolic Computation and Pedagogy | Litle Struggle.
The file structure might be change in the future, but for now, it will be like this:
mathemapy
- core
__init__.py
expr.py
add.py
sub.py
mul.py
div.py
pow.py
numbers.py
symbol.py
__init__.py
I'll expand on this in the future as this continues. I won't be filling the __init__.py
files here; just look into the GitHub code if needed. I'm going to build this with a parent class of Expression. Every other class will be a child of this parent class.
# core/expr.py
from abc import ABC, abstractmethod
class Expression(ABC):
"""
Expression class is the parent for all other classes
"""
@abstractmethod
def evaluate(self):
pass
@abstractmethod
def simplify(self):
pass
@abstractmethod
def __str__(self):
pass
def __repr__(self):
return self.__str__()
def __add__(self, other):
from .add import Add
return Add(self, other)
def __sub__(self, other):
from .sub import Sub
return Sub(self, other)
def __mul__(self, other):
from .mul import Mul
return Mul(self, other)
def __truediv__(self, other):
from .div import Div
return Div(self, other)
def __pow__(self, other):
from .pow import Pow
return Pow(self, other)
def __eq__(self, other: 'Expression') -> bool:
if not isinstance(other, Expression):
return False
# Compare simplified forms
return str(self.simplify()) == str(other.simplify())
def __hash__(self):
return hash(str(self.simplify()))
Let me explain,
ABC and abstractmethod are imported from Python's built-in abc module.
evaluate and simplify are the main methods that will be defined in each child class.
Dunder methods (like
__add__
) are inherited by each class, allowing us to use Python's built-in parsing to convert expressions into classes seamlessly. This eliminates the need for manual parsing for now (note that SymPy supports both methods).__str__
and__repr__
define how each operation and operand is printed. Each child class will define its__str__
method.Because we define the
__eq__
method, we also need__hash__
. This is relatively straightforward. In__eq__
, we check if the simplified forms are equal, not the evaluated forms. This is because evaluation can sometimes return Python objects instead of our custom-defined objects, making it harder to maintain. Therefore, we use the simplify method.Later in
__eq__
, we'll need to handle alternative representations of the same expressions, but for now, we'll keep it simple.
That's all for this post. In the next one, I'll document both the Number and Symbol classes found in numbers.py and symbol.py.
Code is on my GitHub: https://github.com/RezSat/mathemapy
Thank you for reading!